import asyncio
import logging
import os
import queue
import random
import re
import threading
from datetime import datetime

import cv2
from PIL import Image, ImageDraw, ImageFilter, ImageFont
from aiogram import types
from aiogram.dispatcher import FSMContext
from aiogram.dispatcher.filters.state import State, StatesGroup
from aiogram.types import ParseMode
from dateutil.relativedelta import relativedelta
from faker import Faker
from mxcurpy.curp import curp as cp
from rembg import remove as remove_bg

import client
from create_bot import dp
from . import mx_kb
from .mx_country_menu import create_mx
from .mx_pass_generate import mx_pass_generate
from .mx_utils import es_transliterate, is_spanish

fake = Faker()

logger = logging.getLogger(__name__)


def process_generate_signature(user_id, data):
    """Генерация подписи."""
    text = es_transliterate(data.capitalize())
    txt = Image.new("RGBA", (1900, 600), (255, 255, 255, 0))
    go_txt = ImageDraw.Draw(txt)
    fnt1 = ImageFont.truetype("./fonts/1.ttf", size=270)
    go_txt.text(xy=(200, 50), text=f"{text}", font=fnt1, fill="#000000")
    fnt2 = ImageFont.truetype("./fonts/2.ttf", size=130)
    go_txt.text(xy=(800, 50), text=f"{text}", font=fnt2, fill="#000000", stroke_width=1)
    fnt3 = ImageFont.truetype("./fonts/3.ttf", size=180)
    go_txt.text(
        xy=(1400, 50), text=f"{text}", font=fnt3, fill="#000000", stroke_width=1
    )
    fnt4 = ImageFont.truetype("./fonts/4.ttf", size=100)
    go_txt.text(
        xy=(200, 400), text=f"{text}", font=fnt4, fill="#000000", stroke_width=1
    )
    fnt5 = ImageFont.truetype("./fonts/5.ttf", size=150)
    go_txt.text(
        xy=(800, 400), text=f"{text}", font=fnt5, fill="#000000", stroke_width=1
    )
    fnt6 = ImageFont.truetype("./fonts/6.ttf", size=80)
    go_txt.text(xy=(1400, 400), text=f"{text}", font=fnt6, fill="#000000")
    fnt66 = ImageFont.truetype("./fonts/66.ttf", size=80)
    go_txt.text(xy=(1430, 440), text=f"k", font=fnt66, fill="#000000")
    txt_blur = txt.filter(ImageFilter.GaussianBlur(radius=1))
    holst = Image.new("RGBA", (1900, 600), (255, 255, 255, 255))
    choose_signature = Image.alpha_composite(holst, txt_blur)
    choose_signature.save(
        f"./files/mx/mx_pass/photo_usr/{user_id}_choose_signature.png"
    )


def process_passport_photo(user_id):
    try:
        # Load the image and face detection classifier
        img = cv2.imread(
            f"./files/mx/mx_pass/photo_usr/{user_id}.png", cv2.IMREAD_UNCHANGED
        )
        face_cascade = cv2.CascadeClassifier(
            "./data/haarcascade_frontalface_default.xml"
        )

        # Detect faces in the image
        faces = face_cascade.detectMultiScale(img, 1.2, 5)

        # If faces are detected, crop and resize the image
        if len(faces) != 0:
            (x, y, w, h) = faces[0]
            h_top = int(h * 0.4)
            h_bottom = int(h * 0.3)
            w_left = int(w * 0.2)
            w_right = int(w * 0.2)
            x_left = max(0, x - w_left)
            x_right = min(img.shape[1], x + w + w_right)
            w_new = x_right - x_left
            y_top = max(0, y - h_top)
            y_bottom = min(img.shape[0], y + h + h_bottom)
            h_new = y_bottom - y_top

            cropped_img = img[y_top : y_top + h_new, x_left : x_left + w_new]
            cropped_img_pil = Image.fromarray(
                cv2.cvtColor(cropped_img, cv2.COLOR_BGRA2RGBA)
            )

            # Resize the image proportionally to the width of 264px
            target_width = 822
            width_ratio = target_width / cropped_img_pil.width
            new_width = target_width
            new_height = int(cropped_img_pil.height * width_ratio)
            resized_width = cropped_img_pil.resize(
                (new_width, new_height), Image.ANTIALIAS
            )

            # Resize the image proportionally to the height of 345px
            target_height = 1041
            height_ratio = target_height / resized_width.height
            new_height = target_height
            new_width = int(resized_width.width * height_ratio)
            resized_height = resized_width.resize(
                (new_width, new_height), Image.ANTIALIAS
            )

            # Center crop the image to get the width of 264px
            left = (resized_height.width - target_width) / 2
            top = 0
            right = (resized_height.width + target_width) / 2
            bottom = new_height
            cropped_resized = resized_height.crop((left, top, right, bottom))

            # Convert the image to grayscale and keep the alpha channel
            # grayscale_img = cropped_resized.convert("LA").convert("RGBA")
            # grayscale_img.putalpha(cropped_resized.getchannel("A"))

            # Save the processed image with the alpha channel
            cropped_resized.save(f"./files/mx/mx_pass/photo_usr/{user_id}_w.png")
            os.remove(f"./files/mx/mx_pass/photo_usr/{user_id}.png")
        else:
            print(f"No faces found in image for user_id {user_id}")
    except Exception as e:
        print(f"Error processing passport photo for user_id {user_id}: {str(e)}")


class FSM_mx_passport(StatesGroup):
    doc_type = State()
    name = State()
    last_name = State()
    date_of_birth = State()
    place_of_birth = State()
    sex = State()
    issue_date = State()
    pass_number = State()
    curp = State()
    pass_lamination_number = State()
    signature = State()
    holo = State()
    photo = State()
    size = State()
    edit = State()


data_fields = [
    {"title": "Имя", "key": "name"},
    {"title": "Фамилия", "key": "last_name"},
    {"title": "Дата рождения", "key": "date_of_birth"},
    {"title": "Место рождения", "key": "place_of_birth"},
    {"title": "Пол", "key": "sex"},
    {"title": "Дата выдачи", "key": "issue_date"},
    {"title": "Номер паспорта", "key": "pass_number"},
    {"title": "CURP", "key": "curp"},
    {"title": "Номер ламинации паспорта", "key": "pass_lamination_number"},
    {"title": "Подпись", "key": "signature"},
    {"title": "Голограмма", "key": "holo"},
    {"title": "Фото", "key": "photo"},
    {"title": "Размер документа", "key": "size"},
]

male_values = ["мужской", "м", "male", "m"]

female_values = ["женский", "ж", "female", "f"]

places_of_birth = [
    "AGUASCALIENTES",
    "BAJA CALIFORNIA",
    "CAMPECHE",
    "CHIAPAS",
    "CHIHUAHUA",
    "COAHUILA",
    "COLIMA",
    "DISTRITO FEDERAL",
    "DURANGO",
    "GUANAJUATO",
    "GUERRERO",
    "HIDALGO",
    "JALISCO",
    "MEXICO",
    "MORELOS",
    "MICHOACAN",
    "NAYARIT",
    "NUEVO LEON",
    "OAXACA",
    "PUEBLA",
    "QUERETARO",
    "QUINTANA ROO",
    "SAN LUIS POTOSI",
    "SINALOA",
    "SONORA",
    "TABASCO",
    "TAMAULIPAS",
    "TLAXCALA",
    "VERACRUZ",
    "YUCATAN",
    "ZACATECAS",
]


async def data_checkup(user_id: int, state: FSMContext):
    try:
        data = await state.get_data()
        checkup_text = "Данные клиента:\n"
        for field in data_fields:
            if field["key"] in data and data[field["key"]] != None:
                checkup_text += f"✅{field['title']}: {data[field['key']]}\n"
            else:
                checkup_text += f"{field['title']}:\n"
        if "message_to_edit" in data:
            await dp.bot.delete_message(
                chat_id=user_id, message_id=data["message_to_edit"]
            )
        return (await dp.bot.send_message(chat_id=user_id, text=checkup_text))[
            "message_id"
        ]
    except:
        pass


async def delete_user_reply(user_id: int, message_id: int):
    try:
        await dp.bot.delete_message(chat_id=user_id, message_id=message_id)
    except Exception as e:
        logger.warning(f"Unable to delete user message: {e}")


async def mx_pass_name_input(message: types.Message, state: FSMContext):
    await state.update_data(id=message.from_user.id)
    await state.update_data(name=None)
    message_to_edit = await data_checkup(message.from_user.id, state)
    await state.update_data(message_to_edit=message_to_edit)
    question_message = (
        await message.answer(
            "Введите имя✏️\n",
            parse_mode=ParseMode.HTML,
            reply_markup=mx_kb.kb_mx_pass_name,
        )
    )["message_id"]
    logger.info(
        f"Пользователь {message.from_user.username} начал заполнение анкеты на паспорт Мексики."
    )
    await state.update_data(question_message=question_message)
    await FSM_mx_passport.name.set()


@dp.message_handler(state=FSM_mx_passport.name)
async def mx_pass_name_validate(message: types.Message, state: FSMContext):
    await delete_user_reply(message.from_user.id, message.message_id)
    if message.text == "Назад ◀️":
        await create_mx(message)
    else:
        name = None
        data = await state.get_data()

        if "question_message" in data:
            await dp.bot.delete_message(
                chat_id=message.from_user.id, message_id=data["question_message"]
            )
        else:
            logger.warning("question_message not found in state data")

        if is_spanish(message.text):
            name = message.text
        if name is None:
            message_to_edit = await data_checkup(message.from_user.id, state)
            await state.update_data(message_to_edit=message_to_edit)
            question_message = (
                await message.answer(
                    text="❌Введите имя в правильном формате.\n"
                    "<i>Формат ввода: только испанские буквы.</i>",
                    parse_mode=ParseMode.HTML,
                    reply_markup=mx_kb.kb_mx_pass_name,
                )
            )["message_id"]
            await state.update_data(question_message=question_message)
        else:
            await state.update_data(name=name.upper())
            if "edit_mode" in data:
                return await start_generate(message, state)
            await mx_pass_last_name_input(message, state)


async def mx_pass_last_name_input(message: types.Message, state: FSMContext):
    await state.update_data(last_name=None)
    message_to_edit = await data_checkup(message.from_user.id, state)
    await state.update_data(message_to_edit=message_to_edit)
    question_message = (
        await message.answer(
            "Введите фамилию✏️\n",
            parse_mode=ParseMode.HTML,
            reply_markup=mx_kb.kb_mx_pass_last_name,
        )
    )["message_id"]
    await state.update_data(question_message=question_message)
    await FSM_mx_passport.last_name.set()


@dp.message_handler(state=FSM_mx_passport.last_name)
async def mx_pass_last_name_validate(message: types.Message, state: FSMContext):
    await delete_user_reply(message.from_user.id, message.message_id)
    if message.text == "Назад ◀️":
        message_to_edit = await data_checkup(message.from_user.id, state)
        await state.update_data(message_to_edit=message_to_edit)
        await FSM_mx_passport.name.set()
        await mx_pass_name_input(message, state)
    else:
        last_name = None
        data = await state.get_data()

        if "question_message" in data:
            await dp.bot.delete_message(
                chat_id=message.from_user.id, message_id=data["question_message"]
            )
        else:
            logger.warning("question_message not found in state data")

        if is_spanish(message.text):
            last_name = message.text
        if last_name is None:
            message_to_edit = await data_checkup(message.from_user.id, state)
            await state.update_data(message_to_edit=message_to_edit)
            question_message = (
                await message.answer(
                    text="❌Введите фамилию в правильном формате.\n"
                    "<i>Формат ввода: только испанские буквы.</i>",
                    parse_mode=ParseMode.HTML,
                    reply_markup=mx_kb.kb_mx_pass_last_name,
                )
            )["message_id"]
            await state.update_data(question_message=question_message)
        else:
            await state.update_data(last_name=last_name.upper())
            data["sign"] = last_name.capitalize()
            if is_spanish(data["sign"]):
                data["sign"] = es_transliterate(data["sign"])
            if len(data["sign"]) > 5:
                data["sign"] = data["sign"][: random.randint(3, 5)]
            await state.update_data(sign=data["sign"])
            if "edit_mode" in data:
                return await start_generate(message, state)
            await mx_pass_date_of_birth_input(message, state)


async def mx_pass_date_of_birth_input(message: types.Message, state: FSMContext):
    await state.update_data(date_of_birth=None)
    message_to_edit = await data_checkup(message.from_user.id, state)
    await state.update_data(message_to_edit=message_to_edit)
    question_message = (
        await message.answer(
            "Введите дату рождения✏️\n" "<i>Формат ввода: дд.мм.гггг</i>",
            parse_mode=ParseMode.HTML,
            reply_markup=mx_kb.kb_mx_pass_date_of_birth,
        )
    )["message_id"]
    await state.update_data(question_message=question_message)
    await FSM_mx_passport.date_of_birth.set()


@dp.message_handler(state=FSM_mx_passport.date_of_birth)
async def mx_pass_date_of_birth_validate(message: types.Message, state: FSMContext):
    await delete_user_reply(message.from_user.id, message.message_id)
    if message.text == "Назад ◀️":
        message_to_edit = await data_checkup(message.from_user.id, state)
        await state.update_data(message_to_edit=message_to_edit)
        await FSM_mx_passport.last_name.set()
        await mx_pass_last_name_input(message, state)
    else:
        date_of_birth = None
        data = await state.get_data()

        if "question_message" in data:
            await dp.bot.delete_message(
                chat_id=message.from_user.id, message_id=data["question_message"]
            )
        else:
            logger.warning("question_message not found in state data")

        format = "%d.%m.%Y"
        try:
            date_of_birth = datetime.strptime(message.text, format).strftime(format)
        except ValueError:
            pass

        if date_of_birth is None:
            message_to_edit = await data_checkup(message.from_user.id, state)
            await state.update_data(message_to_edit=message_to_edit)
            question_message = (
                await message.answer(
                    text="❌Введите дату в правильном формате.\n"
                    "<i>Формат ввода: дд.мм.гггг</i>",
                    parse_mode=ParseMode.HTML,
                    reply_markup=mx_kb.kb_mx_pass_date_of_birth,
                )
            )["message_id"]
            await state.update_data(question_message=question_message)
        else:
            await state.update_data(date_of_birth=date_of_birth.upper())
            if "edit_mode" in data:
                return await start_generate(message, state)
            await mx_pass_place_of_birth_input(message, state)


async def mx_pass_place_of_birth_input(message: types.Message, state: FSMContext):
    await state.update_data(place_of_birth=None)
    message_to_edit = await data_checkup(message.from_user.id, state)
    await state.update_data(message_to_edit=message_to_edit)
    question_message = (
        await message.answer(
            "Выберите место рождения✏️\n",
            parse_mode=ParseMode.HTML,
            reply_markup=mx_kb.kb_mx_pass_place_of_birth,
        )
    )["message_id"]
    await state.update_data(question_message=question_message)
    await FSM_mx_passport.place_of_birth.set()


@dp.message_handler(state=FSM_mx_passport.place_of_birth)
async def mx_pass_place_of_birth_validate(message: types.Message, state: FSMContext):
    await delete_user_reply(message.from_user.id, message.message_id)
    if message.text == "Назад ◀️":
        message_to_edit = await data_checkup(message.from_user.id, state)
        await state.update_data(message_to_edit=message_to_edit)
        await FSM_mx_passport.last_name_en.set()
        await mx_pass_date_of_birth_input(message, state)
    else:
        place_of_birth = None
        data = await state.get_data()

        if "question_message" in data:
            await dp.bot.delete_message(
                chat_id=message.from_user.id, message_id=data["question_message"]
            )
        else:
            logger.warning("question_message not found in state data")

        if message.text.upper() in places_of_birth:
            place_of_birth = message.text
        if place_of_birth is None:
            message_to_edit = await data_checkup(message.from_user.id, state)
            await state.update_data(message_to_edit=message_to_edit)
            question_message = (
                await message.answer(
                    text="❌Выберите место рождения из списка.",
                    parse_mode=ParseMode.HTML,
                    reply_markup=mx_kb.kb_mx_pass_place_of_birth,
                )
            )["message_id"]
            await state.update_data(question_message=question_message)
        else:
            await state.update_data(place_of_birth=place_of_birth.upper())
            if "edit_mode" in data:
                return await start_generate(message, state)
            await mx_pass_sex_input(message, state)


async def mx_pass_sex_input(message: types.Message, state: FSMContext):
    await state.update_data(sex=None)
    message_to_edit = await data_checkup(message.from_user.id, state)
    await state.update_data(message_to_edit=message_to_edit)
    question_message = (
        await message.answer(
            "Выберите пол✏️\n",
            parse_mode=ParseMode.HTML,
            reply_markup=mx_kb.kb_mx_pass_sex,
        )
    )["message_id"]
    await state.update_data(question_message=question_message)
    await FSM_mx_passport.sex.set()


@dp.message_handler(state=FSM_mx_passport.sex)
async def mx_pass_sex_validate(message: types.Message, state: FSMContext):
    await delete_user_reply(message.from_user.id, message.message_id)
    if message.text == "Назад ◀️":
        message_to_edit = await data_checkup(message.from_user.id, state)
        await state.update_data(message_to_edit=message_to_edit)
        await FSM_mx_passport.date_of_birth.set()
        await mx_pass_place_of_birth_input(message, state)
    else:
        sex = None
        data = await state.get_data()

        if "question_message" in data:
            await dp.bot.delete_message(
                chat_id=message.from_user.id, message_id=data["question_message"]
            )
        else:
            logger.warning("question_message not found in state data")

        if message.text == "Мужской 🙎🏻‍♂️":
            sex = "M"
        elif message.text == "Женский 🙍🏻‍♀️":
            sex = "F"
        else:
            message_to_edit = await data_checkup(message.from_user.id, state)
            await state.update_data(message_to_edit=message_to_edit)
            question_message = (
                await message.answer(
                    text="❌Выберите из предложенных вариантов.",
                    parse_mode=ParseMode.HTML,
                    reply_markup=mx_kb.kb_mx_pass_sex,
                )
            )["message_id"]
            await state.update_data(question_message=question_message)
        if sex == "M" or sex == "F":
            await state.update_data(sex=sex)
            if "edit_mode" in data:
                return await start_generate(message, state)
            await mx_pass_issue_date_input(message, state)


async def mx_pass_issue_date_input(message: types.Message, state: FSMContext):
    await state.update_data(issue_date=None)
    message_to_edit = await data_checkup(message.from_user.id, state)
    await state.update_data(message_to_edit=message_to_edit)
    question_message = (
        await message.answer(
            "Введите дату выдачи✏️\n"
            "<i>Формат ввода: дд.мм.гггг</i>\n"
            "<i>Не раньше 12.06.2016</i>",
            parse_mode=ParseMode.HTML,
            reply_markup=mx_kb.kb_mx_pass_issue_date,
        )
    )["message_id"]
    await state.update_data(question_message=question_message)
    await FSM_mx_passport.issue_date.set()


@dp.message_handler(state=FSM_mx_passport.issue_date)
async def mx_pass_issue_date_validate(message: types.Message, state: FSMContext):
    await delete_user_reply(message.from_user.id, message.message_id)
    if message.text == "Назад ◀️":
        message_to_edit = await data_checkup(message.from_user.id, state)
        await state.update_data(message_to_edit=message_to_edit)
        await mx_pass_sex_input(message, state)
    else:
        issue_date = None
        data = await state.get_data()

        if "question_message" in data:
            await dp.bot.delete_message(
                chat_id=message.from_user.id, message_id=data["question_message"]
            )
        else:
            logger.warning("question_message not found in state data")

        format = "%d.%m.%Y"
        try:
            issue_date = datetime.strptime(message.text, format).strftime(format)
        except ValueError:
            pass

        input_date = None
        try:
            input_date = datetime.strptime(message.text, format)
        except:
            pass
        if input_date == None:
            input_date = "01.01.1800"
        exemplary_date = datetime.strptime("12.06.2016", format)

        if issue_date is None or input_date < exemplary_date:
            message_to_edit = await data_checkup(message.from_user.id, state)
            await state.update_data(message_to_edit=message_to_edit)
            question_message = (
                await message.answer(
                    text="❌Введите дату в правильном формате.\n"
                    "<i>Формат ввода: дд.мм.гггг</i>\n"
                    "<i>Не раньше 12.06.2016</i>",
                    parse_mode=ParseMode.HTML,
                    reply_markup=mx_kb.kb_mx_pass_issue_date,
                )
            )["message_id"]
            await state.update_data(question_message=question_message)
        else:
            await state.update_data(issue_date=issue_date.upper())
            if "edit_mode" in data:
                return await start_generate(message, state)
            await mx_pass_number_input(message, state)


async def mx_pass_number_input(message: types.Message, state: FSMContext):
    await state.update_data(pass_number=None)
    message_to_edit = await data_checkup(message.from_user.id, state)
    await state.update_data(message_to_edit=message_to_edit)
    question_message = (
        await message.answer(
            "Введите номер паспорта✏️\n" "<i>Формат ввода: G12345678</i>",
            parse_mode=ParseMode.HTML,
            reply_markup=mx_kb.kb_mx_pass_number,
        )
    )["message_id"]
    await state.update_data(question_message=question_message)
    await FSM_mx_passport.pass_number.set()


@dp.message_handler(state=FSM_mx_passport.pass_number)
async def mx_pass_number_validate(message: types.Message, state: FSMContext):
    await delete_user_reply(message.from_user.id, message.message_id)
    if message.text == "Назад ◀️":
        message_to_edit = await data_checkup(message.from_user.id, state)
        await state.update_data(message_to_edit=message_to_edit)
        await mx_pass_issue_date_input(message, state)
    else:
        pass_number = None
        data = await state.get_data()

        if "question_message" in data:
            await dp.bot.delete_message(
                chat_id=message.from_user.id, message_id=data["question_message"]
            )
        else:
            logger.warning("question_message not found in state data")

        if message.text == "Сгенерировать":
            pass_number = "G" + fake.numerify(text="########")
        if re.match(r"^[G]\d{8}$", message.text) is not None:
            pass_number = message.text
        if pass_number is None:
            message_to_edit = await data_checkup(message.from_user.id, state)
            await state.update_data(message_to_edit=message_to_edit)
            question_message = (
                await message.answer(
                    text="❌Введите номер паспорта в правильном формате.\n"
                    "<i>Формат ввода: G12345678</i>",
                    parse_mode=ParseMode.HTML,
                    reply_markup=mx_kb.kb_mx_pass_number,
                )
            )["message_id"]
            await state.update_data(question_message=question_message)
        else:
            await state.update_data(pass_number=pass_number)
            if "edit_mode" in data:
                return await start_generate(message, state)
            await mx_pass_curp_input(message, state)


async def mx_pass_curp_input(message: types.Message, state: FSMContext):
    await state.update_data(curp=None)
    message_to_edit = await data_checkup(message.from_user.id, state)
    await state.update_data(message_to_edit=message_to_edit)
    question_message = (
        await message.answer(
            "Введите или сгенерируйте CURP-номер✏️\n"
            "<i>Формат ввода: XXXXyyyyyyXXXXXXXy(yy) X - буква, y - цифра.</i>",
            parse_mode=ParseMode.HTML,
            reply_markup=mx_kb.kb_mx_pass_number,
        )
    )["message_id"]
    await state.update_data(question_message=question_message)
    await FSM_mx_passport.curp.set()


@dp.message_handler(state=FSM_mx_passport.curp)
async def mx_pass_curp_validate(message: types.Message, state: FSMContext):
    await delete_user_reply(message.from_user.id, message.message_id)
    if message.text == "Назад ◀️":
        message_to_edit = await data_checkup(message.from_user.id, state)
        await state.update_data(message_to_edit=message_to_edit)
        await mx_pass_number_input(message, state)
    else:
        curp = None
        data = await state.get_data()

        if "question_message" in data:
            await dp.bot.delete_message(
                chat_id=message.from_user.id, message_id=data["question_message"]
            )
        else:
            logger.warning("question_message not found in state data")

        if message.text is not None:
            curp = message.text
        if message.text == "Сгенерировать":
            print(1)
            mother_name = "X"
            first_last_name = data["last_name"]
            if len(data["last_name"].split(" ")) != 1:
                first_last_name = data["last_name"].split(" ")[0]
                mother_name = data["last_name"].split(" ")[1]

            ten_years = relativedelta(years=10)
            data["date_of_expiry"] = (
                datetime.strptime(data["issue_date"], "%d.%m.%Y") + ten_years
            ).strftime("%d.%m.%Y")
            data["type"] = "P"
            data["code_of_state"] = "MEX"
            curp_sex = "h"
            if data["sex"] == "F":
                curp_sex = "m"
            curp_var = cp(
                names=data["name"],
                lastname=first_last_name,
                second_lastname=mother_name,
                birth_date=data["date_of_birth"].replace(".", "-"),
                birth_state=data["place_of_birth"],
                sex=curp_sex,
            )
            format = "%d.%m.%Y"
            pre_last_char = fake.bothify(text="?")
            if int(datetime.strptime(data["date_of_birth"], format).year) < 2000:
                pre_last_char = fake.bothify(text="#")
            last_char = fake.bothify(text="#")
            curp = curp_var[:16] + pre_last_char + last_char
            print(curp)
        if curp is None:
            message_to_edit = await data_checkup(message.from_user.id, state)
            await state.update_data(message_to_edit=message_to_edit)
            question_message = (
                await message.answer(
                    text="Введите или сгенерируйте CURP-номер✏️\n"
                    "<i>Формат ввода: XXXXyyyyyyXXXXXXXy(yy) X - буква, y - цифра.</i>",
                    parse_mode=ParseMode.HTML,
                    reply_markup=mx_kb.kb_mx_pass_number,
                )
            )["message_id"]
            await state.update_data(question_message=question_message)
        else:
            await state.update_data(curp=curp)
            if "edit_mode" in data:
                return await start_generate(message, state)
            await mx_pass_lamination_number_input(message, state)


async def mx_pass_lamination_number_input(message: types.Message, state: FSMContext):
    await state.update_data(pass_lamination_number=None)
    message_to_edit = await data_checkup(message.from_user.id, state)
    await state.update_data(message_to_edit=message_to_edit)
    question_message = (
        await message.answer(
            "Введите номер ламинации паспорта✏️\n" "<i>Формат ввода: 12345678</i>",
            parse_mode=ParseMode.HTML,
            reply_markup=mx_kb.kb_mx_pass_lamination_number,
        )
    )["message_id"]
    await state.update_data(question_message=question_message)
    await FSM_mx_passport.pass_lamination_number.set()


@dp.message_handler(state=FSM_mx_passport.pass_lamination_number)
async def mx_pass_lamination_number_validate(message: types.Message, state: FSMContext):
    await delete_user_reply(message.from_user.id, message.message_id)
    if message.text == "Назад ◀️":
        message_to_edit = await data_checkup(message.from_user.id, state)
        await state.update_data(message_to_edit=message_to_edit)
        await mx_pass_curp_input(message, state)
    else:
        pass_lamination_number = None
        data = await state.get_data()

        if "question_message" in data:
            await dp.bot.delete_message(
                chat_id=message.from_user.id, message_id=data["question_message"]
            )
        else:
            logger.warning("question_message not found in state data")

        if message.text == "Сгенерировать":
            pass_lamination_number = fake.numerify(text="########")
        if re.match(r"^\d{8}$", message.text) is not None:
            pass_lamination_number = message.text
        if pass_lamination_number is None:
            message_to_edit = await data_checkup(message.from_user.id, state)
            await state.update_data(message_to_edit=message_to_edit)
            question_message = (
                await message.answer(
                    text="❌Введите номер ламинации паспорта в правильном формате.\n"
                    "<i>Формат ввода: 12345678</i>",
                    parse_mode=ParseMode.HTML,
                    reply_markup=mx_kb.kb_mx_pass_lamination_number,
                )
            )["message_id"]
            await state.update_data(question_message=question_message)
        else:
            await state.update_data(pass_lamination_number=pass_lamination_number)
            if "edit_mode" in data:
                return await start_generate(message, state)
            await mx_pass_signature_input(message, state)


async def mx_pass_signature_input(user_id, state: FSMContext):
    await state.update_data(signature=None)
    if type(user_id) == types.Message:
        user_id = user_id.from_user.id
    message_to_edit = await data_checkup(user_id, state)
    await state.update_data(message_to_edit=message_to_edit)
    data = await state.get_data()

    process_generate_signature(user_id=user_id, data=data["sign"])

    kb = types.InlineKeyboardMarkup()
    kb.add(
        types.InlineKeyboardButton(text="1", callback_data="sig_1"),
        types.InlineKeyboardButton(text="2", callback_data="sig_2"),
        types.InlineKeyboardButton(text="3", callback_data="sig_3"),
    )
    kb.add(
        types.InlineKeyboardButton(text="4", callback_data="sig_4"),
        types.InlineKeyboardButton(text="5", callback_data="sig_5"),
        types.InlineKeyboardButton(text="6", callback_data="sig_6"),
    )
    kb.add(types.InlineKeyboardButton(text="Не ставить", callback_data="sig_0"))
    kb.add(types.InlineKeyboardButton(text="Назад ◀️", callback_data="sig_back"))

    photo_path = (
        "./files/mx/mx_pass/photo_usr/" + str(user_id) + "_choose_signature.png"
    )  # Замените на путь к вашей картинке
    with open(photo_path, "rb") as photo:
        question_message = (
            await dp.bot.send_photo(
                chat_id=user_id,
                photo=photo,
                caption="Выберите тип подписи:",
                reply_markup=kb,
            )
        )["message_id"]
    await state.update_data(question_message=question_message)
    await FSM_mx_passport.signature.set()


@dp.callback_query_handler(state=FSM_mx_passport.signature)
async def mx_pass_signature_validate(
    callback_query: types.CallbackQuery, state: FSMContext
):
    if callback_query.data == "sig_back":
        data = await state.get_data()
        await dp.bot.delete_message(
            chat_id=callback_query.from_user.id, message_id=data["question_message"]
        )
        message_to_edit = await data_checkup(callback_query.from_user.id, state)
        await state.update_data(message_to_edit=message_to_edit)
        await mx_pass_lamination_number_input(callback_query.from_user.id, state)
    else:
        await dp.bot.answer_callback_query(callback_query.id)
        signature = int(callback_query.data.split("_")[1])
        await state.update_data(signature=int(signature))
        logger.info(f"Пользователь {callback_query.from_user.username} выбрал подпись.")

        data = await state.get_data()
        if "question_message" in data:
            await dp.bot.delete_message(
                chat_id=callback_query.from_user.id, message_id=data["question_message"]
            )
        else:
            logger.warning("question_message_id not found in state data")
        if "edit_mode" in data:
            return await start_generate(callback_query.from_user.id, state)
        message_to_edit = await data_checkup(callback_query.from_user.id, state)
        await state.update_data(message_to_edit=message_to_edit)
        await mx_pass_holo_input(callback_query.from_user.id, state)


async def mx_pass_holo_input(user_id, state: FSMContext):
    await state.update_data(holo=None)
    if type(user_id) == types.Message:
        user_id = user_id.from_user.id
    message_to_edit = await data_checkup(user_id, state)
    await state.update_data(message_to_edit=message_to_edit)
    data = await state.get_data()

    kb = types.InlineKeyboardMarkup()
    kb.add(
        types.InlineKeyboardButton(text="1", callback_data="holo_1"),
        types.InlineKeyboardButton(text="2", callback_data="holo_2"),
    )
    kb.add(types.InlineKeyboardButton(text="Не ставить", callback_data="holo_0"))
    kb.add(types.InlineKeyboardButton(text="Назад ◀️", callback_data="holo_pass_back"))

    holo_path = (
        "./files/mx/mx_pass/holo_preview.png"  # Замените на путь к вашей картинке
    )
    with open(holo_path, "rb") as holo:
        question_message = (
            await dp.bot.send_photo(
                chat_id=user_id,
                photo=holo,
                caption="Выберите голограмму:",
                reply_markup=kb,
            )
        )["message_id"]
    await state.update_data(question_message=question_message)
    await FSM_mx_passport.holo.set()


@dp.callback_query_handler(state=FSM_mx_passport.holo)
async def mx_pass_holo_validate(
    callback_query: types.CallbackQuery or types.Message, state: FSMContext
):
    message = ""
    if type(callback_query) == types.Message:
        message = "holo_pass_back"
    if type(callback_query) == types.CallbackQuery:
        message = callback_query.data
    if message == "holo_pass_back":
        message_to_edit = await data_checkup(callback_query.from_user.id, state)
        await state.update_data(message_to_edit=message_to_edit)
        await mx_pass_signature_input(callback_query.from_user.id, state)
    else:
        await dp.bot.answer_callback_query(callback_query.id)
        holo = int(callback_query.data.split("_")[1])
        await state.update_data(holo=int(holo))
        logger.info(
            f"Пользователь {callback_query.from_user.username} выбрал голограмму."
        )

        data = await state.get_data()
        if "question_message" in data:
            await dp.bot.delete_message(
                chat_id=callback_query.from_user.id, message_id=data["question_message"]
            )
        else:
            logger.warning("question_message_id not found in state data")
        if "edit_mode" in data:
            return await start_generate(callback_query.from_user.id, state)
        message_to_edit = await data_checkup(callback_query.from_user.id, state)
        await state.update_data(message_to_edit=message_to_edit)
        await mx_pass_photo_input(callback_query.from_user.id, state)


async def mx_pass_photo_input(user_id: int or types.Message, state: FSMContext):
    if type(user_id) == types.Message:
        user_id = user_id.from_user.id
    await state.update_data(photo=None)
    message_to_edit = await data_checkup(user_id, state)
    await state.update_data(message_to_edit=message_to_edit)
    question_message = (
        await dp.bot.send_message(
            chat_id=user_id,
            text="Загрузите фотографию\n"
            "❗️Требования к фотографии:\n"
            "➖ Фотография должна быть загружена без сжатия , "
            "нажимаем скрепку - файл - выбрать фото\n"
            "➖ На фотографии должно быть видно плечи, глаза открыты\n"
            "➖ Кадр должен быть в хорошем освещении\n"
            "➖ Лицо должно быть под прямым углом к камере\n"
            "❗️ Поддерживаемые форматы: PNG, JPG, JPEG ❗️",
            reply_markup=mx_kb.kb_mx_back,
        )
    )["message_id"]
    await state.update_data(question_message=question_message)
    await FSM_mx_passport.photo.set()


@dp.message_handler(
    content_types=types.ContentType.DOCUMENT, state=FSM_mx_passport.photo
)
async def process_photo(message: types.Message, state: FSMContext):
    if message.text == "Назад ◀️":
        message_to_edit = await data_checkup(message.from_user.id, state)
        await state.update_data(message_to_edit=message_to_edit)
        await mx_pass_holo_input(message, state)
    else:
        data = await state.get_data()
        # Check if the message has a document
        # Check if the document is in the required format (PNG)
        file_info = await dp.bot.get_file(message.document.file_id)
        await message.delete()
        # if file_info.file_path.lower().endswith(".png"):
        # Download the document and save it as user_id.png

        photo_path = f"./files/mx/mx_pass/photo_usr/{message.from_user.id}.png"
        await dp.bot.download_file(file_info.file_path, photo_path)

        out = remove_bg(Image.open(photo_path))
        out = out.convert("RGBA")
        out.save(f"./files/mx/mx_pass/photo_usr/{message.from_user.id}.png")
        # Check if the image has an alpha channel
        img = Image.open(photo_path).convert("RGBA")
        if img.mode == "RGBA":
            # Process the photo in a separate thread
            thread = threading.Thread(
                target=process_passport_photo, args=(message.from_user.id,)
            )
            thread.start()
            # Проверка состояния потока каждую секунду с использованием asyncio.sleep
            while thread.is_alive():
                await asyncio.sleep(1)
            # Check if the processed photo exists
            processed_photo_path = (
                f"./files/mx/mx_pass/photo_usr/{message.from_user.id}_w.png"
            )
            if os.path.exists(processed_photo_path):
                data = await state.get_data()
                question_message = data.get("question_message")
                try:
                    await dp.bot.delete_message(
                        chat_id=message.chat.id, message_id=question_message
                    )
                    message_to_edit = await data_checkup(message.from_user.id, state)
                    await dp.bot.delete_message(
                        chat_id=message.chat.id, message_id=message_to_edit
                    )
                except:
                    pass
                await state.update_data(photo="Загружено")
                await mx_pass_size_input(message, state)
            else:
                await dp.bot.send_message(
                    chat_id=message.chat.id,
                    text="❌ Фотография не соответствует требованиям.\n"
                    "ИИ не смог обработать вашу фотографию.\n"
                    "Это происходит, если фото не соответствует требованиям, "
                    "проверьте что расширение файла PNG, "
                    "либо загрузите другое изображение.",
                )
        else:
            await dp.bot.send_message(
                chat_id=message.chat.id,
                text="❌ Фотография не соответствует требованиям.\n"
                "ИИ не смог обработать вашу фотографию.\n"
                "Это происходит, если фото не соответствует требованиям, "
                "проверьте что расширение файла PNG, "
                "либо загрузите другое изображение.",
            )
        # elif file_info.file_path.lower().endswith(".jpg"):
        #     # Download the document and save it as user_id.png
        #     photo_path = f"./files/mx/mx_pass/photo_usr/{message.from_user.id}.png"
        #     await dp.bot.download_file(file_info.file_path, f"./files/mx/mx_pass/photo_usr/{message.from_user.id}.jpg")
        #     # AI work
        #     out = remove_bg(Image.open(f"./files/mx/mx_pass/photo_usr/{message.from_user.id}.jpg"))
        #     out.save(f'./files/mx/mx_pass/photo_usr/{message.from_user.id}.png')
        #     # Check if the image has an alpha channel
        #     img = Image.open(photo_path).convert("RGBA")
        #     if img.mode == "RGBA":
        #         # Process the photo in a separate thread
        #         thread = threading.Thread(
        #             target=process_passport_photo, args=(message.from_user.id,)
        #         )
        #         thread.start()
        #         # Проверка состояния потока каждую секунду с использованием asyncio.sleep
        #         while thread.is_alive():
        #             await asyncio.sleep(1)
        #         # Check if the processed photo exists
        #         processed_photo_path = (
        #             f"./files/mx/mx_pass/photo_usr/{message.from_user.id}_w.png"
        #         )
        #         if os.path.exists(processed_photo_path):
        #             data = await state.get_data()
        #             question_message = data.get("question_message")
        #             try:
        #                 await dp.bot.delete_message(
        #                     chat_id=message.chat.id, message_id=question_message
        #                 )
        #                 message_to_edit = await data_checkup(message.from_user.id, state)
        #                 await dp.bot.delete_message(
        #                     chat_id=message.chat.id, message_id=message_to_edit
        #                 )
        #             except:
        #                 pass
        #             await state.update_data(photo='Загружено')
        #             await kz_pass_size_input(message, state)
        #         else:
        #             await dp.bot.send_message(
        #                 chat_id=message.chat.id,
        #                 text="❌ Фотография не соответствует требованиям.\n"
        #                 "ИИ не смог обработать вашу фотографию.\n"
        #                 "Это происходит, если фото не соответствует требованиям, "
        #                 "проверьте что расширение файла PNG, "
        #                 "либо загрузите другое изображение.",
        #             )
        #     else:
        #         await dp.bot.send_message(
        #             chat_id=message.chat.id,
        #             text="❌ Фотография не соответствует требованиям.\n"
        #             "ИИ не смог обработать вашу фотографию.\n"
        #             "Это происходит, если фото не соответствует требованиям, "
        #             "проверьте что расширение файла PNG, "
        #             "либо загрузите другое изображение.",
        #         )

        # elif file_info.file_path.lower().endswith(".jpeg"):
        #     # Download the document and save it as user_id.png
        #     photo_path = f"./files/mx/mx_pass/photo_usr/{message.from_user.id}.png"
        #     await dp.bot.download_file(file_info.file_path, f"./files/mx/mx_pass/photo_usr/{message.from_user.id}.jpeg")
        #     # AI work
        #     out = remove_bg(Image.open(f"./files/mx/mx_pass/photo_usr/{message.from_user.id}.jpeg"))
        #     out.save(f'./files/mx/mx_pass/photo_usr/{message.from_user.id}.png')
        #     # Check if the image has an alpha channel
        #     img = Image.open(photo_path).convert("RGBA")
        #     if img.mode == "RGBA":
        #         # Process the photo in a separate thread
        #         thread = threading.Thread(
        #             target=process_passport_photo, args=(message.from_user.id,)
        #         )
        #         thread.start()
        #         # Проверка состояния потока каждую секунду с использованием asyncio.sleep
        #         while thread.is_alive():
        #             await asyncio.sleep(1)
        #         # Check if the processed photo exists
        #         processed_photo_path = (
        #             f"./files/mx/mx_pass/photo_usr/{message.from_user.id}_w.png"
        #         )
        #         if os.path.exists(processed_photo_path):
        #             data = await state.get_data()
        #             question_message = data.get("question_message")
        #             try:
        #                 await dp.bot.delete_message(
        #                     chat_id=message.chat.id, message_id=question_message
        #                 )
        #                 message_to_edit = await data_checkup(message.from_user.id, state)
        #                 await dp.bot.delete_message(
        #                     chat_id=message.chat.id, message_id=message_to_edit
        #                 )
        #             except:
        #                 pass
        #             await state.update_data(photo='Загружено')
        #             await kz_pass_size_input(message, state)

        #         else:
        #             await dp.bot.send_message(
        #                 chat_id=message.chat.id,
        #                 text="❌ Фотография не соответствует требованиям.\n"
        #                 "ИИ не смог обработать вашу фотографию.\n"
        #                 "Это происходит, если фото не соответствует требованиям, "
        #                 "проверьте что расширение файла PNG, "
        #                 "либо загрузите другое изображение.",
        #             )
        #     else:
        #         await dp.bot.send_message(
        #             chat_id=message.chat.id,
        #             text="❌ Фотография не соответствует требованиям.\n"
        #             "ИИ не смог обработать вашу фотографию.\n"
        #             "Это происходит, если фото не соответствует требованиям, "
        #             "проверьте что расширение файла PNG, "
        #             "либо загрузите другое изображение.",
        #         )
        # else:
        #     await dp.bot.send_message(
        #         chat_id=message.chat.id,
        #         text="❌ Фотография не соответствует требованиям.\n"
        #         "ИИ не смог обработать вашу фотографию.\n"
        #         "Это происходит, если фото не соответствует требованиям, "
        #         "проверьте что расширение файла PNG, "
        #         "либо загрузите другое изображение.",
        #     )


async def mx_pass_size_input(message: types.Message, state: FSMContext):
    user_id = message.from_user.id
    await state.update_data(size=None)
    message_to_edit = await data_checkup(user_id, state)
    await state.update_data(message_to_edit=message_to_edit)
    question_message = (
        await dp.bot.send_message(
            chat_id=user_id,
            text="Выберите размер документа",
            reply_markup=mx_kb.kb_mx_pass_size,
        )
    )["message_id"]
    await FSM_mx_passport.size.set()
    await state.update_data(question_message=question_message)


@dp.message_handler(state=FSM_mx_passport.size)
async def mx_pass_size_validate(message: types.Message, state: FSMContext):
    if message.text == "Назад ◀️":
        message_to_edit = await data_checkup(message.from_user.id, state)
        await state.update_data(message_to_edit=message_to_edit)
        await mx_pass_photo_input(message, state)
    else:
        size_type = None
        if message.text == "📃 На листе А4":
            size_type = "A4"
        elif message.text == "🪪 В размер документа":
            size_type = "DOC"
        elif message.text == "🖼 На фоне":
            size_type = "На фоне"
        else:
            message_to_edit = await data_checkup(message.from_user.id, state)
            await state.update_data(message_to_edit=message_to_edit)
            question_message = (
                await dp.bot.send_message(
                    chat_id=message.from_user.id,
                    text="Выберите размер документа",
                    reply_markup=mx_kb.kb_mx_pass_size,
                )
            )["message_id"]
            return await state.update_data(question_message=question_message)
        await message.delete()
        await state.update_data(size=size_type)
        data = await state.get_data()
        logger.info(f"Пользователь {message.from_user.id} выбрал размер документа")

        if "question_message" in data:
            await dp.bot.delete_message(
                chat_id=message.from_user.id, message_id=data["question_message"]
            )
        else:
            logger.warning("question_message_id not found in state data")
        if "edit_mode" in data:
            return await start_generate(message, state)
        message_to_edit = await data_checkup(message.from_user.id, state)
        await state.update_data(message_to_edit=message_to_edit)
        await start_generate(message, state)


async def start_generate(user_id: types.Message or int, state: FSMContext):
    if type(user_id) == types.Message:
        user_id = user_id.from_user.id
    message_to_delete = await dp.bot.send_message(
        chat_id=user_id, text="Ожидайте генерируется..."
    )
    data = await state.get_data()
    result_queue = queue.Queue()
    thread = threading.Thread(target=mx_pass_generate, args=(data, result_queue))
    thread.start()
    thread.join()
    result = result_queue.get()
    if "Error" in result:
        await dp.bot.send_message(
            chat_id=user_id, text="❌Ошибка при генерации изображения"
        )
        # await dp.bot.send_message(chat_id=363661148, text=result)
    else:
        await dp.bot.delete_message(
            chat_id=user_id, message_id=message_to_delete["message_id"]
        )
        # with open(result + "_wm.png", "rb") as photo:
        with open(f"./files/mx/mx_pass/photo_usr/{user_id}_wm.png", "rb") as doc_wm:
            await dp.bot.send_document(chat_id=user_id, document=doc_wm)
            await dp.bot.send_message(
                chat_id=user_id,
                text="Завершите покупку документа.",
                reply_markup=mx_kb.kb_mx_pass_finish,
            )
        await state.reset_state(with_data=False)


@dp.callback_query_handler(text="mx_change_pass", state="*")
async def mx_change_pass(call: types.CallbackQuery, state: FSMContext):
    kb = types.ReplyKeyboardMarkup(one_time_keyboard=True)
    await call.message.delete()
    for field in data_fields:
        kb.add(types.KeyboardButton(text=f'{field["title"]}'))
    message_to_edit = (
        await call.message.answer(
            text="Выберите параметр, который хотите изменить", reply_markup=kb
        )
    )["message_id"]
    await state.update_data(message_to_edit=message_to_edit)
    await FSM_mx_passport.edit.set()


@dp.message_handler(state=FSM_mx_passport.edit)
async def edit_field(message: types.Message, state: FSMContext):
    data = await state.get_data()
    await dp.bot.delete_message(
        chat_id=message.from_user.id, message_id=data["message_to_edit"]
    )
    await message.delete()
    key = None
    for field in data_fields:
        if field["title"] == message.text:
            key = field["key"]
    if key is None:
        return await message.answer("❌Выберите параметр через клавиатуру")
    await state.update_data(edit_mode=1)
    func_name = key
    print(func_name)
    func_name_with_input = "mx_pass_" + func_name + "_input"

    # Получаем ссылку на функцию с использованием имени и вызываем ее
    function_to_call = globals()[func_name_with_input]
    await function_to_call(message, state)


@dp.callback_query_handler(text="mx_pay_pass", state="*")
async def command_pay_mx_pass(callback: types.CallbackQuery, state: FSMContext):
    await state.finish()
    await state.update_data(pay_country="mx_pass")
    await client.command_promo_quest(callback, state)


# @dp.callback_query_handler(text="kz_exit_pass", state="*")
# async def command_exit_kz_pass(callback: types.CallbackQuery, state: FSMContext):
#     await dp.bot.send_message(chat_id=callback.from_user.id, text='Выход')
#     await state.finish()
